/**
 * 
 */
package com.baijia.tianxiao.connect.util;

import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baijia.tianxiao.connect.config.Constants;
import com.baijia.tianxiao.connect.daemon.KeepLiveCheckThread;
import com.baijia.tianxiao.connect.enums.CloseReasonEnum;
import com.baijia.tianxiao.connect.route.api.ConnectSessionBindApi;
import com.baijia.tianxiao.connect.route.api.enums.MsgType;
import com.baijia.tianxiao.connect.route.api.model.TianxiaoConnectSession;
import com.baijia.tianxiao.connect.route.api.model.TxMessage;

/**
 * @author leiruiqi
 *
 */
@Service("tianxiaoConnectUtil")
public class TianxiaoConnectUtil {
	
	private static Logger logger = LoggerFactory.getLogger(TianxiaoConnectUtil.class); 
	
	
	public static final ConcurrentHashMap<String,WebSocketSession> sessionMap = new ConcurrentHashMap<String,WebSocketSession>();  
	
	public static final ConcurrentHashMap<String,String> deviceIdMap = new ConcurrentHashMap<String,String>();
	
	@Resource
	private ConnectSessionBindApi connectSessionBindApi;
	
	private String localIp;
	
	private Integer localPort;
	
	
    
    public Integer getLocalPort() {
		return localPort;
	}

	public void setLocalPort(Integer localPort) {
		this.localPort = localPort;
	}

	@PostConstruct
    public void init(){
    	
    	
		try {
			localIp = getRealIp();
			logger.info("local address="+localIp);
			
		} catch (Exception e) {
			logger.error("get loal ip exception", e);
		}
		
		KeepLiveCheckThread keepLive = new KeepLiveCheckThread(sessionMap);
    	keepLive.start();
    	
    	
    }
    
    public static String getRealIp() throws SocketException {
        String localip = null;// 本地IP，如果没有配置外网IP则返回它
        //String netip = null;// 外网IP
  
        Enumeration<NetworkInterface> netInterfaces = 
            NetworkInterface.getNetworkInterfaces();
        InetAddress ip = null;
        boolean finded = false;// 是否找到外网IP
        while (netInterfaces.hasMoreElements() && !finded) {
            NetworkInterface ni = netInterfaces.nextElement();
            Enumeration<InetAddress> address = ni.getInetAddresses();
            while (address.hasMoreElements()) {
                ip = address.nextElement();
                if (ip.isSiteLocalAddress() 
                        && !ip.isLoopbackAddress() 
                        && ip.getHostAddress().indexOf(":") == -1) {// 内网IP
                    localip = ip.getHostAddress();
                }
            }
        }
      
        return localip;
        
    }
	
	public void addSession(String nameKey,String deviceKey,WebSocketSession session){
		
		deviceIdMap.put(deviceKey,nameKey);
		sessionMap.put(nameKey, session);	
		
		/*String jsonStr = connectionSesion2JsonStr(model);
		try {
			CacheUtil.set(model.getSessionKey(), jsonStr,3600*12);
		} catch (Exception e) {
			logger.error("",e);
		}*/
	}
	
	public static WebSocketSession getSession(String nameKey){
		return sessionMap.get(nameKey);	
	}
	
	public static WebSocketSession getSessionByDeviceKey(String deviceKey){
		String sessionKey = getSessionKeyByDeviceId(deviceKey);
		if(StringUtils.isNoneBlank(sessionKey)){
			return sessionMap.get(sessionKey);	
		}
		return null;
	}
	
	public static void closeSessionByReason(WebSocketSession session,CloseReasonEnum reason,String message){
		
		try {
			if(session.isOpen()){
				if(StringUtils.isNoneBlank(message)){
					session.sendMessage(new TextMessage(message));
				}
				session.close(CloseStatus.NORMAL.withReason(reason.name()));
			}
			
		} catch (Exception e) {
			logger.error("close session exception",e);
		}	
	}
	
	public static boolean deviceIdExist(String deviceId){
		String sessionKey = getSessionKeyByDeviceId(deviceId);
		return StringUtils.isBlank(sessionKey);
	}
	
	public static String getSessionKeyByDeviceId(String deviceId){
		return deviceIdMap.get(deviceId);
	}
	
	/*public WebSocketSession removeSession(String nameKey){
		WebSocketSession session =  sessionMap.remove(nameKey);
		return session;
	}*/
	
	public void removeSession(WebSocketSession session ){
		
		String deviceKey =  (String)session.getAttributes().get(Constants.BIZ_TYPE)+ (String)session.getAttributes().get(Constants.DEVICE_ID);
		
		sessionMap.remove((String)session.getAttributes().get(Constants.SESSION_USERNAME));
		deviceIdMap.remove(deviceKey);
		
	}
	
	public void unbindSession(WebSocketSession session ){
		TianxiaoConnectSession model = createTianxiaoSessionCacheModel(session);
		connectSessionBindApi.unbindSession(model);
	}
	
	public void bindSession(WebSocketSession session ){
		TianxiaoConnectSession model = createTianxiaoSessionCacheModel(session);
		connectSessionBindApi.bindSession(model);
	}
	
	public void addBindSessionAttribute(WebSocketSession session ){
		TianxiaoConnectSession model = createTianxiaoSessionCacheModel(session);
		connectSessionBindApi.addBindAttribute(model);
	}
	
	public TianxiaoConnectSession createTianxiaoSessionCacheModel(WebSocketSession session){
		TianxiaoConnectSession model = new TianxiaoConnectSession();
		model.setSessionIp(localIp+":"+localPort);
		model.setCreateTime((Long)session.getAttributes().get(Constants.LAST_MSG_TIME));
		model.setSessionKey((String)session.getAttributes().get(Constants.SESSION_USERNAME));
		model.setSessionId(session.getId());
		model.setBizType((String)session.getAttributes().get(Constants.BIZ_TYPE));
		model.setUserId((String)session.getAttributes().get(Constants.USER_ID));
		model.setDeviceType((String)session.getAttributes().get(Constants.DEVICE_TYPE));
		model.setDeviceId((String)session.getAttributes().get(Constants.DEVICE_ID));
		Map<String,Object> extents = (Map<String,Object>)session.getAttributes().get(Constants.EXTENTS_ATTRIBUTE);
		if(extents!=null){
			model.setExtensions(extents);
		}
		return model;
	}
	
	
	public static String connectionSesion2JsonStr(TianxiaoConnectSession connectSession){
		String jsonStr = JSON.toJSONString(connectSession);
		return jsonStr;
	}
	
	/*public static String createTxSessionKey(String domain,String bizType,String userId,String deviceDomain,String deviceType,String deviceId){
		
		if(StringUtils.isBlank(domain)||StringUtils.isBlank(bizType)||StringUtils.isBlank(userId)||StringUtils.isBlank(deviceDomain)||StringUtils.isBlank(deviceType)||StringUtils.isBlank(deviceId)){
			return null;
		}
		
		String websocket_username = domain+"-" + bizType+"-"+userId+"-"+deviceDomain;
		return websocket_username;
	}*/
	
	public static ConcurrentHashMap<String,WebSocketSession> getTianxiaoSessionMap(){
		return sessionMap;
	}
	
	public static Boolean containSession(String sessionKey){
		return sessionMap.containsKey(sessionKey);
	}
	
	public static String buildTxMessageErr(String code,String errMsg){
		TxMessage txMessage = new TxMessage();
		txMessage.setType(MsgType.err.name());
		JSONObject json = new JSONObject();
		json.put("code", code);
		json.put("msg", errMsg);
		
		txMessage.setData(json.toJSONString());
		
		String jsonStr =  JSON.toJSONString(txMessage);
		return jsonStr;
	}
	
	public static boolean sendMessage(WebSocketSession session,TextMessage message){
		try {
			if(!session.isOpen()){
				return false;
			}
			session.sendMessage(message);
			return true;
		} catch (IOException e) {
			logger.error("sendMessage error",e);
			return false;
		}
	}
	
	public static void main(String[] args) {
		String code = "tokenTimeOut";
		String message = "you are bad";
		String errorStr = TianxiaoConnectUtil.buildTxMessageErr(code,message);
		System.out.println(errorStr);
	}
	
}
